package com.vote.www.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vote.www.core.StaticMap;
import com.vote.www.domain.Czjweixininfo;
import com.vote.www.domain.vo.AccessOpenId;
import com.vote.www.domain.vo.WeixinInfo;
import com.vote.www.utils.CommonHttp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import tangwj.person.dao.ResourceDao;

import java.io.UnsupportedEncodingException;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created by 汤伟杰 on 2017/5/11.
 */
@Service
public class WeixininfoService {
    @Autowired
    private ResourceDao resourceDao;
    @Autowired
    private JdbcTemplate jdbcTemplate;


    /**
     * 删除微信信息token缓存
     */
    public void checkCodeEndtime() {
       /* Map<String, String> map = StaticMap.getAccessOpenIdMap();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if(entry.getValue()==null){
                map.remove(entry.getKey());
            }else{
                AccessOpenId vo = JSONObject.parseObject(entry.getValue(),AccessOpenId.class);
                if(vo.getEndtime()-System.currentTimeMillis()>=0){
                    map.remove(entry.getKey());
                }
            }

        }*/
    }

    /**
     * 刷新code值
     * @param code
     * @return
     */
    public void getRefreshAccessToken(String code) throws Exception {
        AccessOpenId openIdEntity = StaticMap.getAccessOpenIdMap(code);
        String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+StaticMap.appid+"&grant_type=refresh_token&refresh_token="+openIdEntity.getRefresh_token();
        System.out.println("请求刷新token:"+url);
        Map<String, Object> refresh_token = CommonHttp.send(url, "get", null);
        if(refresh_token.get("errcode")!=null){
            throw new Exception("请求刷新token失败！返回值："+JSONObject.toJSONString(refresh_token));
        }
        System.out.println("返回值:"+JSONObject.toJSONString(refresh_token));
        setOpenIdEntity(refresh_token,code);

    }

    /**
     *
     * @param code
     * @return
     * {
    "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",
    "openid":"OPENID",
    "scope":"SCOPE",
    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    }
     */
    public void getAccessToken(String code) throws Exception {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+StaticMap.appid+"&secret="+StaticMap.secret+"&code="+code+"&grant_type=authorization_code";
        System.out.println("请求token:"+url);
        Map<String, Object> access_token_map = CommonHttp.send(url, "get", null);
        if(access_token_map.get("errcode")!=null){
            throw new Exception("请求token失败！返回值："+JSONObject.toJSONString(access_token_map));
        }
        System.out.println("返回值:"+JSONObject.toJSONString(access_token_map));
        setOpenIdEntity(access_token_map,code);

    }
    public void getWeixinInfoByToken(String code) throws Exception {
        AccessOpenId openIdEntity = StaticMap.getAccessOpenIdMap(code);
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+openIdEntity.getAccess_token()+"&openid="+openIdEntity.getOpenid()+"&lang=zh_CN";
        System.out.println("请求微信信息:"+url);
        Map<String, Object> weixinInfo = CommonHttp.send(url, "get", null);
        if(weixinInfo.get("errcode")!=null){
            throw new Exception("请求token获取微信用户信息失败！返回值："+JSONObject.toJSONString(weixinInfo));
        }
        System.out.println("返回值:"+JSONObject.toJSONString(weixinInfo));
        setWeixinInfo(weixinInfo,openIdEntity.getOpenid());


    }
    private void setOpenIdEntity(Map<String,Object> data,String code){
        AccessOpenId openIdEntity = StaticMap.getAccessOpenIdMap(code);
        if(openIdEntity==null){
            openIdEntity = new AccessOpenId();
        }
        openIdEntity.setAccess_token(String.valueOf(data.get("access_token")));
        openIdEntity.setCode(code);
        openIdEntity.setCreatetime(new Date());
        openIdEntity.setExpires_in(Long.valueOf(String.valueOf(data.get("expires_in"))));
        openIdEntity.setScope(String.valueOf(data.get("scope")));
        openIdEntity.setUnionid(String.valueOf(data.get("unionid")));
        openIdEntity.setOpenid(String.valueOf(data.get("openid")));
        openIdEntity.setRefresh_token(String.valueOf(data.get("refresh_token")));
        openIdEntity.setEndtime(System.currentTimeMillis()+openIdEntity.getExpires_in()*1000);
        StaticMap.getAccessOpenIdMap().put(code, JSONObject.toJSONString(openIdEntity));
    }

    public void setWeixinInfo(Map<String,Object> weixinInfoMap,String openid) {
        String json = StaticMap.getWeixinInfoJson(openid);

        if(json==null){
            //保存到缓存里
            weixinInfoMap.put("update", 1);
            StaticMap.getWeixinInfoJson().put(openid, JSONObject.toJSONString(weixinInfoMap));
        }else {
            Map<String,Object> mapType = JSON.parseObject(json,Map.class);
            if(String.valueOf(mapType.get("nickname")).equals(String.valueOf(weixinInfoMap.get("nickname")))
                    ||String.valueOf(mapType.get("headimgurl")).equals(String.valueOf(weixinInfoMap.get("headimgurl")))
                    ||String.valueOf(mapType.get("province")).equals(String.valueOf(weixinInfoMap.get("province")))
                    ||String.valueOf(mapType.get("city")).equals(String.valueOf(weixinInfoMap.get("city")))
                    ||String.valueOf(mapType.get("country")).equals(String.valueOf(weixinInfoMap.get("country")))
                    ){
                weixinInfoMap.put("update","1");//告诉他要更新数据库中的数据
            }
            //保存到缓存里
            StaticMap.getWeixinInfoJson().put(openid, JSONObject.toJSONString(weixinInfoMap));

        }
    }

    /**
     * URL 转码
     *
     * @return String
     * @author lifq
     * @date 2015-3-17 下午04:10:28
     */
    public static String getURLEncoderString(String str) {
        String result = "";
        if (null == str) {
            return "";
        }
        try {
            result = java.net.URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static String getAccessToken() throws Exception {

        String uri = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+StaticMap.appid+"&secret="+StaticMap.secret;
        Map<String,Object> map = null;
        try {
            map = CommonHttp.send(uri, "get", null);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("获取 access_token 失败!");
        }
//        System.out.println(JSONObject.toJSONString(map));
        StaticMap.getAccessToken().setCreatetime(new Date());
        StaticMap.getAccessToken().setExpires_in(Integer.parseInt(String.valueOf(map.get("expires_in"))));
        StaticMap.getAccessToken().setEndtime(new Date().getTime()+(StaticMap.getAccessToken().getExpires_in()*1000));
        return  String.valueOf(map.get("access_token"));
//        map.get("expires_in");
    }
    public static String getTicket(String access_token) throws Exception {

        String uri = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi";
        Map<String,Object> map = null;
        try {
            map = CommonHttp.send(uri, "get", null);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("获取 ticket 失败!");
        }
        if((Integer)map.get("errcode")==1){
            throw new Exception("获取 ticket 失效!");
        }
        return  String.valueOf(map.get("ticket"));

    }


    public static Map<String, String> sign(String jsapi_ticket, String url) throws DigestException {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        System.out.println(string1);

        signature=SHA1(string1);


        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);
        ret.put("signature", signature);

        return ret;
    }


    /**
     * SHA1 安全加密算法
     *
     * @return
     * @throws DigestException
     */
    public static String SHA1(String decrypt) throws DigestException {
        //获取信息摘要 - 参数字典排序后字符串
//        String decrypt = getOrderByLexicographic(maps);
        try {
            //指定sha1算法
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(decrypt.getBytes());
            //获取字节数组
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString().toLowerCase();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new DigestException("签名错误！");
        }
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }


    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
    public WeixinInfo getWeixinInfo(String code) throws Exception {
        AccessOpenId openIdEntity = StaticMap.getAccessOpenIdMap(code);
        //设置token

        checkCodeEndtime();
        if(openIdEntity==null){
            getAccessToken(code);//得到token
            getWeixinInfoByToken(code);//得到微信信息
        }else if(openIdEntity.getEndtime()<=System.currentTimeMillis()){
            getRefreshAccessToken(code);//刷新token
            getWeixinInfoByToken(code);//得到微信信息
        }
        //从缓存获取微信信息
        StaticMap.getAccessOpenIdMap();
        StaticMap.getWeixinInfoJson();
        openIdEntity = StaticMap.getAccessOpenIdMap(code);
        return StaticMap.weixinInfoJsonTo(openIdEntity.getOpenid());
    }

    public WeixinInfo getWeixinUserInfoByOpenid(String openid) throws Exception {

        Czjweixininfo czjweixininfo = (Czjweixininfo)jdbcTemplate.queryForObject("select * from czj_weixininfo where openid='" + openid + "'", new BeanPropertyRowMapper(Czjweixininfo.class));
        WeixinInfo weixinInfo = new WeixinInfo();
        weixinInfo.setOpenid(czjweixininfo.getOpenid());
        weixinInfo.setNickname(czjweixininfo.getNickname());
        weixinInfo.setSex(czjweixininfo.getSex());
        weixinInfo.setProvince(czjweixininfo.getProvince());
        weixinInfo.setCity(czjweixininfo.getCity());
        weixinInfo.setCountry(czjweixininfo.getCountry());
        weixinInfo.setHeadimgurl(czjweixininfo.getHeadimgurl());
        weixinInfo.setUnionid(czjweixininfo.getUnionid());
        return weixinInfo;
    }

    public Map<String,Object> getWeixinGongzhonghao(String code) throws Exception {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("subscribe", 0);
        Map<String, Object> tokenmap = getAccessTokenGzh();
        getWeixinInfo(code);
        AccessOpenId access = StaticMap.getAccessOpenIdMap(code);
        String openid=access.getOpenid();
        String token = String.valueOf(tokenmap.get("access_token"));

        Map<String, Object> weixininfoMap = getFocusWeixinGzh(token, openid);
        if(Integer.valueOf(String.valueOf(weixininfoMap.get("subscribe")))==1){
            map.put("subscribe", 1);
        }
        return map;
    }

    /**
     * 获取token（和是否关注微信公众号关联）
     * @return
     * @throws Exception
     */
    public Map<String, Object> getAccessTokenGzh() throws Exception {
        System.out.println("请求token！"+"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+StaticMap.appid+"&secret="+StaticMap.secret);
        Map<String,Object> tokenmap = CommonHttp.send("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+StaticMap.appid+"&secret="+StaticMap.secret, "get", null);
        if(tokenmap.get("errcode")!=null){
            throw new Exception("请求token失败！返回值："+JSONObject.toJSONString(tokenmap));
        }
        System.out.println(JSONObject.toJSONString(tokenmap));
        return tokenmap;
    }
    /**
     * 获取是否关注微信公众号
     * @param token
     * @param openid
     * @return
     * @throws Exception
     */
    public Map<String,Object> getFocusWeixinGzh(String token,String openid) throws Exception {
        System.out.println("获取是否关注微信公众号：https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + token + "&openid=" + openid + "&lang=zh_CN");
        Map<String, Object> map = CommonHttp.send("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + token + "&openid=" + openid + "&lang=zh_CN", "get", null);
        if(map.get("errcode")!=null){
            throw new Exception("获取公众号个人信息失败！返回值："+JSONObject.toJSONString(map));
        }
        System.out.println("返回："+JSONObject.toJSONString(map));
        return map;
    }

    public static void main(String[] args) throws Exception {
        WeixininfoService weixininfoService = new WeixininfoService();
        weixininfoService.getWeixinGongzhonghao("1");

    }
}
